#pragma once
#include <cmath>

class Vector3
{
public:
    float x, y, z;

    Vector3() = default;
    Vector3(const Vector3 &vector) : x(vector.x), y(vector.y), z(vector.z) {}
    Vector3(float xValue, float yValue, float zValue) : x(xValue), y(yValue), z(zValue) {}

    // operator overload
    Vector3 &operator=(const Vector3 &rhs)
    {
        x = rhs.x;
        y = rhs.y;
        z = rhs.z;
        return *this;
    }

    bool operator==(const Vector3 &rhs) const
    {
        return x == rhs.x && y == rhs.y && z == rhs.z;
    }

    bool operator!=(const Vector3 &rhs) const
    {
        return !(*this == rhs);
    }

    void zero() { x = y = z = 0; }

    Vector3 operator-() const { return Vector3(-x, -y, -z); }
    Vector3 operator+(const Vector3 &a) const
    {
        return Vector3(x + a.x, y + a.y, z + a.z);
    }

    Vector3 operator-(const Vector3 &a) const
    {
        return Vector3(x - a.x, y - a.y, z - a.z);
    }

    Vector3 operator*(float a) const
    {
        return Vector3(x * a, y * a, z * a);
    }

    Vector3 operator/(float a) const
    {
        float oneOvera = 1.0f / a;
        return Vector3(x * oneOvera, y * oneOvera, z * oneOvera);
    }

    Vector3 &operator+=(const Vector3 &a)
    {
        x += a.x;
        y += a.y;
        z += a.z;
        return *this;
    }
    Vector3 &operator-=(const Vector3 &a)
    {
        x -= a.x;
        y -= a.y;
        z -= a.z;
        return *this;
    }
    Vector3 &operator*=(float a)
    {
        x *= a;
        y *= a;
        z *= a;
        return *this;
    }
    Vector3 &operator/=(float a)
    {
        float oneOvera = 1.0f / a;
        x /= oneOvera;
        y /= oneOvera;
        z /= oneOvera;
        return *this;
    }

    void normalize()
    {
        float magSq = x * x + y * y + z * z;
        if (magSq > 0)
        {
            float oneOver = 1.0f / std::sqrt(magSq);
            x *= oneOver;
            y *= oneOver;
            z *= oneOver;
        }
    }

    float operator*(const Vector3 &a) const
    {
        return x * a.x + y * a.y + z * a.z;
    }
};

inline float length(const Vector3 &vec)
{
    return sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z);
}

inline Vector3 crossProduct(const Vector3 &a, const Vector3 &b)
{
    return Vector3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
}

// 标量相乘
inline Vector3 operator*(float k, const Vector3 &v)
{
    return Vector3(k * v.x, k * v.y, k * v.z);
}

inline Vector3 operator*(const Vector3 &v, float k)
{
    return k * v;
}

inline float distance(const Vector3 &start, const Vector3 &end)
{
    float dx = start.x - end.x;
    float dy = start.y - end.y;
    float dz = start.z - end.z;

    return sqrt(dx * dx + dy * dy + dz * dz);
}


//提供一个全局零向量

extern const Vector3 kZeroVector;